/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/lib/mydns.h,v 1.44 2002/08/31 08:33:25 bboy Exp $
	libmydns.h: Header file for the MyDNS library.

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#ifndef _MYDNS_H
#define _MYDNS_H

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>

#include <mysql.h>
#include <errmsg.h>

#include <netinet/in.h>

#include <bits.h>
#include <header.h>


/* Table names */
#define	MYDNS_SOA_TABLE	"soa"
#define	MYDNS_RR_TABLE		"rr"
#define	MYDNS_PTR_TABLE	"ptr"

/* Configurable table names */
extern char mydns_soa_table_name[PATH_MAX];
extern char mydns_rr_table_name[PATH_MAX];
extern char mydns_ptr_table_name[PATH_MAX];

/* If this is nonzero, an 'active' field is assumed to exist in the table, and
	only active rows will be loaded by mydns_*_load() */
extern int mydns_soa_use_active;
#define mydns_set_soa_use_active(mysql)	\
				(mydns_soa_use_active = column_exists((mysql), mydns_soa_table_name, "active"))
extern int mydns_rr_use_active;
#define mydns_set_rr_use_active(mysql)	\
				(mydns_rr_use_active = column_exists((mysql), mydns_rr_table_name, "active"))
extern int mydns_ptr_use_active;
#define mydns_set_ptr_use_active(mysql)	\
				(mydns_ptr_use_active = column_exists((mysql), mydns_ptr_table_name, "active"))

/* This is set by mydns_set_soa_use_xfer */
extern int mydns_soa_use_xfer;
#define mydns_set_soa_use_xfer(mysql)	\
				(mydns_soa_use_xfer = column_exists((mysql), mydns_soa_table_name, "xfer"))

/* This is set by mydns_set_rr_use_stamp (currently unimplemented - for future IXFR support */
extern int mydns_rr_use_stamp;
#define mydns_set_rr_use_stamp(mysql)	\
				(mydns_rr_use_stamp = column_exists((mysql), mydns_rr_table_name, "stamp"))

/* NOTE: `type' is listed at the end so that we can possibly set the value of `aux' for
	convenience based on the RR type; for example, an `A' record might store the IP in `aux'. */
#define	MYDNS_SOA_FIELDS	"id,origin,ns,mbox,serial,refresh,retry,expire,minimum,ttl"
#define	MYDNS_RR_FIELDS	"id,zone,name,data,aux,ttl,type"
#define	MYDNS_PTR_FIELDS	"id,ip,name,ttl"

/* Clear MySQL error/errno error */
#define	MYDNS_CLEARERR(m)	if (m) m->net.last_errno = 0; errno = 0;

/* Does the specified string end with a dot? */
#define	ENDS_WITH_DOT(s)	(s && (s[strlen(s)-1] == '.'))

/* Convert str to unsigned int */
#define atou(s) (u_int32_t)strtoul(s, (char **)NULL, 10)

/* Size ranges for various bits of DNS data */
#define	DNS_MAXPACKETLEN_TCP		65536		/* Use 64k for TCP */
#define	DNS_MAXPACKETLEN_UDP		512		/* RFC1035: "512 octets or less" */
#define	DNS_MAXNAMELEN				255		/* RFC1035: "255 octets or less" */
#define	DNS_MAXLABELLEN			63			/* RFC1035: "63 octets or less" */
#define	DNS_POINTER_MASK			0xC0
#define	DNS_QUERYBUFSIZ			512		/* Used as buffer size for MySQL queries */

/* Default values in SOA records */
#define	DNS_DEFAULT_REFRESH		28800
#define	DNS_DEFAULT_RETRY			7200
#define	DNS_DEFAULT_EXPIRE		604800
#define	DNS_DEFAULT_MINIMUM		86400
#define	DNS_DEFAULT_TTL			86400
#define	DNS_MINIMUM_TTL			300

/* Common errors */
enum task_error_t {
	ERR_NONE = 0,					/* No error */
	ERR_ZONE_NOT_FOUND,			/* "Zone not found" */
	ERR_NO_AXFR,					/* "AXFR disabled" */
	ERR_RR_NAME_TOO_LONG,		/* "Name too long in RR" */
	ERR_Q_BUFFER_OVERFLOW,		/* "Input name buffer overflow" */
	ERR_Q_INVALID_COMPRESSION,	/* "Unknown compression method" */
	ERR_Q_NAME_TOO_LONG,			/* "Question name too long" */
	ERR_NO_CLASS,					/* "Unknown class" */
	ERR_NAME_FORMAT,				/* "Invalid name format" */
};

/* Query classes */
typedef enum _dns_class_t
{
	DNS_C_IN = 1,
	DNS_C_CHAOS = 3,
	DNS_C_HESIOD = 4,
	DNS_C_ANY = 255
} dns_class_t;

/* Query types */
typedef enum _dns_qtype_t
{
	DNS_T_NONE = 0,				/* None/invalid */
	DNS_T_A = 1,					/* Address */
	DNS_T_NS = 2,					/* Nameserver */
	DNS_T_MD = 3,					/* Mail dest */
	DNS_T_MF = 4,					/* Mail forwarder */
	DNS_T_CNAME = 5,				/* Canonical name */
	DNS_T_SOA = 6,					/* Start of authority */
	DNS_T_MB = 7,					/* Mailbox name */
	DNS_T_MG = 8,					/* Mail group */
	DNS_T_MR = 9,					/* Mail rename */
	DNS_T_NULL = 10,				/* Null */
	DNS_T_WKS = 11,				/* Well known service */
	DNS_T_PTR = 12,				/* IP -> fqdn mapping */
	DNS_T_HINFO = 13,				/* Host info */
	DNS_T_MINFO = 14,				/* Mailbox info */
	DNS_T_MX = 15,					/* Mail routing info */
	DNS_T_TXT = 16,				/* Text */
	DNS_T_RP = 17,					/* Responsible person */
	DNS_T_AFSDB = 18,				/* AFS cell database */
	DNS_T_X25 = 19,				/* X_25 calling address */
	DNS_T_ISDN = 20,				/* ISDN calling address */
	DNS_T_RT = 21,					/* Router */
	DNS_T_NSAP = 22,				/* NSAP address */
	DNS_T_NSAP_PTR = 23,			/* Reverse NSAP lookup (depreciated) */
	DNS_T_SIG = 24,				/* Security signature */
	DNS_T_KEY = 25,				/* Security key */
	DNS_T_PX = 26,					/* X.400 mail mapping */
	DNS_T_GPOS = 27,				/* Geographical position (withdrawn) */
	DNS_T_AAAA = 28,				/* IPv6 Address */
	DNS_T_LOC = 29,				/* Location info */
	DNS_T_NXT = 30,				/* Next domain (security) */
	DNS_T_EID = 31,				/* Endpoint identifier */
	DNS_T_NIMLOC = 32,			/* Nimrod Locator */
	DNS_T_SRV = 33,				/* Server */
	DNS_T_ATMA = 34,				/* ATM Address */
	DNS_T_NAPTR = 35,				/* Naming Authority Pointer */
	DNS_T_KX = 36,					/* Key Exchange */
	DNS_T_CERT = 37,				/* Certification record */
	DNS_T_A6 = 38,					/* IPv6 address (deprecates AAAA) */
	DNS_T_DNAME = 39,				/* Non-terminal DNAME (for IPv6) */
	DNS_T_SINK = 40,				/* Kitchen sink (experimentatl) */
	DNS_T_OPT = 41,				/* EDNS0 option (meta-RR) */
	DNS_T_TSIG = 250,				/* Transaction signature */
	DNS_T_IXFR = 251,				/* Incremental zone transfer */
	DNS_T_AXFR = 252,				/* Zone transfer */
	DNS_T_MAILB = 253,			/* Transfer mailbox records */
	DNS_T_MAILA = 254,			/* Transfer mail agent records */
	DNS_T_ANY = 255,				/* Any */
	DNS_T_MAX = 65536
} dns_qtype_t;


/* Opcodes */
typedef enum _dns_opcode_t		/* DNS opcode types */
{
	DNS_OPCODE_QUERY = 0,		/* Query */
	DNS_OPCODE_IQUERY,			/* Inverse query */
	DNS_OPCODE_STATUS				/* Status request */
} dns_opcode_t;


/* Return codes */
typedef enum _dns_rcode_t		/* DNS return codes */
{
	DNS_R_NOERROR = 0,			/* No error */
	DNS_R_FORMERR = 1,			/* The name server was unable to interpret the query */
	DNS_R_SERVFAIL = 2,			/* The name server had an internal error */
	DNS_R_NXDOMAIN = 3,			/* The specified domain name does not exist */
	DNS_R_NOTIMP = 4,				/* The requested kind of query is not implemented */
	DNS_R_REFUSED = 5,			/* Query refused for policy reasons */
	DNS_R_YXDOMAIN = 6,			/* ??? */
	DNS_R_YXRRSET = 7,			/* ??? */
	DNS_R_NXRRSET = 8,			/* ??? */
	DNS_R_NOTAUTH = 9,			/* Not authoritative? */
	DNS_R_NOTZONE = 10,			/* ??? */
	DNS_R_BADVERS = 16,			/* ??? */
} dns_rcode_t;

/* The record types */
typedef enum _dns_rrtype_t		/* DNS record types (for MyDNS) */
{
	DNS_RRTYPE_SOA,
	DNS_RRTYPE_RR,
	DNS_RRTYPE_PTR,
} dns_rrtype_t;


/*
**  Structures describing each record type
*/
typedef struct _mydns_soa							/* `soa' table data (zones of authority) */
{
	u_int32_t	id;
	u_char		origin[DNS_MAXNAMELEN+1];
	u_char		ns[DNS_MAXNAMELEN+1];
	u_char		mbox[DNS_MAXNAMELEN+1];
	u_int32_t	serial;
	u_int32_t	refresh;
	u_int32_t	retry;
	u_int32_t	expire;
	u_int32_t	minimum;
	u_int32_t	ttl;

	struct _mydns_soa *next;
} MYDNS_SOA;

typedef struct _mydns_rr							/* `rr' table data (resource records) */
{
	u_int32_t	id;
	u_int32_t	zone;
	u_char		name[DNS_MAXNAMELEN+1];
	dns_qtype_t	type;
	u_char		data[DNS_MAXNAMELEN+1];
	u_int64_t	aux;
	u_int32_t	ttl;

	struct _mydns_rr *next;
} MYDNS_RR;

typedef struct _mydns_ptr							/* `ptr' (ip-to-name mappings) */
{
	u_int32_t	id;
	u_int32_t	ip;
	u_char		name[DNS_MAXNAMELEN+1];
	u_int32_t	ttl;

	struct _mydns_ptr *next;
} MYDNS_PTR;


/* ip.c */
extern u_int32_t mydns_revstr_ip4(u_char *);

/* misc.c */
extern int column_exists(MYSQL *, const char * const, const char * const);

/* str.c */
extern char *mydns_qtype_str(dns_qtype_t);
extern char *mydns_class_str(dns_class_t);
extern char *mydns_opcode_str(dns_opcode_t);
extern char *mydns_rcode_str(dns_rcode_t);

/* soa.c */
extern u_int32_t mydns_soa_count(MYSQL *);
extern void mydns_set_soa_table_name(char *);
extern inline MYDNS_SOA *mydns_parse_soa(MYSQL_ROW);
extern int mydns_soa_load(MYSQL *, MYDNS_SOA **, unsigned char *);
extern MYDNS_SOA *mydns_soa_dup(MYDNS_SOA *, int);
extern inline size_t mydns_soa_size(MYDNS_SOA *);
extern inline void _mydns_soa_free(MYDNS_SOA *);
#define mydns_soa_free(p) if (p) _mydns_soa_free(p), p = NULL

/* rr.c */
extern u_int32_t mydns_rr_count(MYSQL *);
extern void mydns_set_rr_table_name(char *);
extern inline MYDNS_RR *mydns_parse_rr(MYSQL_ROW);
extern int mydns_rr_load(MYSQL *, MYDNS_RR **, u_int32_t, dns_qtype_t, unsigned char *, unsigned char *);
extern MYDNS_RR *mydns_rr_dup(MYDNS_RR *, int);
extern inline size_t mydns_rr_size(MYDNS_RR *);
extern inline void _mydns_rr_free(MYDNS_RR *);
#define mydns_rr_free(p) if (p) _mydns_rr_free(p), p = NULL

/* ptr.c */
extern u_int32_t mydns_ptr_count(MYSQL *);
extern void mydns_set_ptr_table_name(char *);
extern inline MYDNS_PTR *mydns_parse_ptr(MYSQL_ROW);
extern int mydns_ptr_load(MYSQL *, MYDNS_PTR **, struct in_addr *);
extern MYDNS_PTR *mydns_ptr_dup(MYDNS_PTR *, int);
extern inline size_t mydns_ptr_size(MYDNS_PTR *);
extern inline void _mydns_ptr_free(MYDNS_PTR *);
#define mydns_ptr_free(p) if (p) _mydns_ptr_free(p), p = NULL


/* unencode.c */
extern u_char *name_unencode(u_char *start, size_t slen, u_char *current, u_char *dest, size_t destsize);


#endif /* !_MYDNS_H */

/* vi:set ts=3: */
